Skip to content

feat(web): agent 控制台重构 — i18n/主题/探活/slashcmd/配置热重载#56

Open
wuchulonly wants to merge 27 commits into
masterfrom
feat/agent-console-aligned
Open

feat(web): agent 控制台重构 — i18n/主题/探活/slashcmd/配置热重载#56
wuchulonly wants to merge 27 commits into
masterfrom
feat/agent-console-aligned

Conversation

@wuchulonly

Copy link
Copy Markdown
Contributor

概述

Agent 控制台重构分支:前端去 chatbot 味 + i18n + 主题系统,后端新增探活/本地 agent/统一命令目录/配置热重载/结构化评估。共 9 个逻辑提交。

改动分组

提交 内容
chore 移除 cyber-ui submodule,收敛 .gitignore
fix(provider) LLM 协议推断 / model 覆盖(AISCAN_MODEL)/ 能力对齐
feat(probe) pkg/probe 连接与 LLM 主动探活
feat(slashcmd) 统一 slash 命令目录 + TUI 固定盒子渲染
refactor(agent) 评估器结构化断言 / 事件 JSON / 上下文截断
refactor(tools) 扫描采集 / spray / gogo / zombie + 输出精简
feat(web) 后端会话 / SSE / sqlite store / 配置热重载 / webagent
feat(web-ui) 前端重构:i18n / 主题 / viewer / 原子组件
chore(web) 重建内嵌静态资源 web/static

规模

  • 全部:395 文件,+13674 / −4619
  • 手写代码(排除 web/static 构建产物 + lock):183 文件,+12980 / −4033
  • 后端 Go:+4243(其中测试 +1831,占 43%)

备注

  • 本分支为大重构「事后拆分」,中间提交不保证单独可编译;最终 HEAD 完整一致。
  • scratch/临时文件(preview.html 等)已排除,未提交。

🤖 Generated with Claude Code

Nathaniel Leonardjoi and others added 27 commits July 7, 2026 02:58
cyber-ui 已 vendored 进 src/{ui,markdown,viewer,terminal-view,lib/theme},
删除 submodule 引用;整理忽略规则(运营产物、静态构建残留、泄漏配置)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- base_url 空 provider 时按 host 推断 anthropic/openai 协议,避免误走
  openai 协议对 Anthropic-only 网关空体 404
- ANTHROPIC_MODEL 等 provider-env 降级为 fallback-only,新增 AISCAN_MODEL
  自有命名空间覆盖,避免 prod env 静默盖过 web 配置
- endpoint hint + provider 能力对齐,补充 parity/hint 测试

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
新增 pkg/probe(conn/llm)做真实可达性探测:llm_available 只表示
client 建好,不查 404;顶栏 LLMHealth 主动 testLLM 才真正探活。
web 侧 probe 端点 + 回归测试。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 新增 pkg/slashcmd 单一目录,驱动 REPL + web + 菜单;hub 按 Scope 路由;
  /shell 退役改 !bash
- TUI /spaces /nodes /messages 改 renderFixedBox(定宽 + ANSI 裁剪 +
  runewidth CJK 对齐);/status 的 IOA URL 走 redactIOAURL 脱敏
- 补 banner/catalog 渲染回归测试

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- evaluator 结构化断言(criteria→count/exists 确定性 Go + judge 有据判定)
- event_json 评估事件序列化 + provider 热切换测试
- truncate/clip 上下文裁剪调整与测试

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- scan collector/jsonl_writer、spray、gogo、zombie、toolargs 调整
- core/output 颜色/格式精简,移除 tool_data
- headless request、tavily 搜索小改

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SSE hub 终端事件可靠投递、config 热重载(ReloadProvider 热切换 provider)
- store 迁移到 sqlite(删除内存 store),会话/scan 级联删除、agent 稳定身份
- webagent 上传路径注入 LLM、eval 转发 extractEventData 修复
- slashcmd web 端点、localagent 本地启动;补 config_reload/command/sse/
  eval_forward/upload 回归测试

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 中英 i18n(i18n/locales,MiSans CJK 字体),LanguageToggle/主题系统
- vendored cyber-ui 进 src/{ui,markdown,viewer,terminal-view,lib/theme};
  手搓原子组件收敛(Button/Badge/Callout/Field/StatTile…)
- 聊天页去 chatbot 味:身份归左 rail、AI=蓝、composer 融成单一 well;
  LLMHealth 主动探活、ModelCombobox 模型选择
- 删除独立 scan 页/侧栏/report 视图,scanning 内联进 agent 聊天

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
前端重构后重新构建 web/static(i18n/主题/字体 chunk、MiSans 子集),
更新编译期内嵌的 hash 化资源。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
原子层回归共享库单一真相源:aiscan 贡献的原子已合并进 cyber-ui
(chainreactors/cyber-ui#1),这里改回从子模块消费,删除 vendored 副本。

- 重新引入 web/frontend/cyber-ui 子模块(pin 合并后 6b80eb3)
- vite/tsconfig 恢复 @aspect/ui + @aspect/theme alias → 子模块 packages
- tailwind preset 改指子模块 theme
- 全量改写 import:@/ui→@aspect/ui(16)、@/lib/theme→@aspect/theme(50)
- 删除 vendored src/ui、src/lib/theme(33 文件)
- markdown/viewer/terminal 保持 vendored(aiscan 深度定制的复合组件,
  非原子),仅把其内部引用改指子模块
- ConfirmDialog 已在上游去 i18n 耦合,新增 LocalizedConfirmProvider
  在 main.tsx 注入本地化 labels,保住中文确认框

验证:tsc --noEmit 绿;vite build 全量 2041 模块转换 + emit 成功。
web/static 内嵌产物运行时等价(仅 import 解析路径变化),部署时
npm run build 重生成;本机 web/static/assets 为 root-owned 历史残留未动。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the local replace bridge and pin github.com/chainreactors/sdk to
v0.3.4-0.20260707120839-686d4bfa2b2b (chainreactors/sdk#31, merged), which
populates gogo's pkg.ChainExec when the SDK injects neutron templates. This
fixes the ants "worker exits from panic" nil-pointer that aborted exploit
scanning on every open host.

TestGogoEngineInjectsChainExecutor now passes against the real pinned SDK
(no replace).

Refs #51

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…A1019)

- errcheck: store_sqlite tx.Rollback 两处显式忽略返回值
- nilerr: 上传结果非 JSON 时兜底合并两条重复分支,消除 nil-return(真重构,非 nolint)
- gosec G120: handler 上传先 http.MaxBytesReader 封顶 body,再行级 nolint(这版 gosec sanitizer 列表为空,识别不了缓解)
- misspell: banner_render_test 注释 colour→color
- unused: 删除退役 /shell 遗留的死代码 handleShellCommand
- SA1019+死代码: 端口配置已改走 resource-provider 管道(gogo 自设 utils.PrePort),
  删除冗余且无人读取的 PortPreset / installLocalPortPreset;测试改为断言真正的
  provider 契约 GogoConfig("port")

注:tidy 的 go-runewidth 提为直接依赖已随 64694d7(sdk bump 的 go mod tidy)进入 HEAD。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
删除 64694d7 bump 后不再被引用的旧版 chainreactors/sdk
(v0.3.4-0.20260704194820-4141f24c2bcd)哈希;`go mod tidy` 现已干净,
修复 CI 的 tidy job。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
agent 侧 fenceTerminalOutput 给多行 REPL/shell 输出包 Markdown 代码围栏
(/status /provider /nodes 等盒子画符+列对齐只在定宽保换行下成立);web
聊天按 Markdown 散文渲染会把单换行折成空格+比例字体,面板塌成一行。
前端 MarkdownContent 对含换行的无 info-string fenced block 也判为块级,
避免退化成行内 pill。单行输出仍走散文。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
子模块推进 6b80eb3→4832385(第二刀原子 + terminal 包)。aiscan 接过去:

- 设计系统第二刀收敛:手搓 <button>→@aspect/ui Button(App/SessionList/
  ConfigPanel/ScanProgressInline 等),消费新原子 DisclosureCard/ResultLine/
  Switch;新建 aiscan-local AiPanel(抽「AI 研判」面板签名)、AgentVoiceCard
  (抽「AI 语气」卡壳,viewer 三处共用)
- terminal-view 迁入子模块:删 vendored src/terminal-view(465 行),
  vite/tsconfig 加 @aspect/terminal alias,AgentTerminal/TerminalDetails
  改从 @aspect/terminal 消费

验证:tsc --noEmit 绿。web/static 内嵌产物部署时重建。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cyber-ui 作为源码消费(vite 把 @aspect/* alias 到其 packages),Tailwind
content 必须也扫它,否则仅在子模块内用到的 utility(如 DisclosureCard
的 grid-rows-[0fr]/[1fr] 折叠动画)不会生成、静默失效(展开/折叠不动)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
反映第二刀原子/terminal 迁移(a45e8f5)与 Tailwind cyber-ui 扫描修复,
重新构建 web/static 内嵌产物(hash 化 JS/CSS 更新)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bump chainreactors/proton 至 471f99e(含预过滤修复):上游 AC 行级
预过滤用非重叠 leftmost-first Find 迭代挑候选模板,长字面量
("begin rsa private key")被其它已加载模板的更短字面量("begin")
遮蔽 → 多密钥文件里 156 条规则只命中约 5 条(private-key/jwt/
stripe/database 全漏)。上游已改用 FindAllOverlapping(chainreactors/proton#3)。

proton -j 输出改用 nuclei-style 连字符键(template-id/template-name),
不再直接 marshal 内部 parsers.Result 泄漏 template_id(该共享类型
被 scan 等其它数据路径依赖,不能改库 tag);新增 jsonFinding 结构体。

修复 pkg/tools/proton 4 个 E2E:DetectsAllCategories / ProtonJSON /
Pipe_CatToProtonWithExpression / Pipe_ShellToPseudoToShell。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TestMITMCapture_ServerFirst_Fallback 客户端读 deadline(8s)与 MITM
内部 3s peek 超时裕度过小,-race + CI 争用下回退+透传的 goroutine
调度被拖过 8s → 间歇超时(PR #56 CI test job 即挂在此)。放宽到 30s;
该测试断言的是回退正确性(收到 SSH banner + 0 抓流),不是延迟。

webagent readSessionMessage/readSessionUpdate 同类 5s deadline(等异步
pty.sessions 消息,满载下曾超时)一并放宽到 20s。

均为测试侧墙钟裕度调整,不碰任何生产超时。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
架构简化:
- 删除 pkg/slashcmd 包,命令元数据改为从 tui.Command 单一来源提取
- SlashSpec 类型移入 webproto,hub 路由简化为 3 行 map
- 删除 catalog_test.go 同步守卫(不再有两份数据需要同步)

正确性修复:
- generateID 改用 crypto/rand 消除纳秒级碰撞导致的静默丢数据
- sanitizeMessagesForSave else 分支改为全结构拷贝,不再丢新增字段
- proxy truncate 改为 rune-safe,修复多字节字符被切断
- SetDataDir/DataDir 加 sync.Mutex 消除竞态
- Color.Dim 统一使用 ANSIDim 常量
- stringVal 增加 float64/bool 处理,修复 timeline 丢数字参数

去重与简化:
- mustJSON 统一到 webproto.MustJSON
- stripANSI wrapper 删除,直接调用
- dispatch 内联到 dispatchPayload
- runScanViaAgent/runScanLocally 共享 completeJob

性能:
- WebSocket upgrader 缓存到 pool 构造期
- regexp.MustCompile 提升到包级别
- hasTool O(n)→O(1) map 查找
- isTerminalEvent 使用 slices.Contains

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- pkg/probe → pkg/agent/probe (probe 依赖 agent.Provider,归属更自然)
- 合并 LLMTestRequest / LLMModelsRequest → LLMProbeRequest (仅差一个 Model 字段)
- 删除 ConnTestResponse wrapper (单字段 struct,返回 []ConnCheck 即可)
- 删除 ChatPayload.Persist (PersistMaxTurns > 0 已隐含 persist)
- 删除 SlashSpec.WebMenu (构造时始终 true,前端从不读取)
- embed ChatPayload 到 SendMessageRequest,消除 handler 中手工字段拷贝
- parseChatPayload 每条 chat 消息只调一次 (之前 dispatch + run 各调一次)
- extractEventData 在 forwardAgentEvent 中只调一次 (之前每个 case 重复调)
- 内联 snippet / proxyHTTPClient 到唯一调用点

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@M09Ic

M09Ic commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review follow-up: 后端简化与修复 (2 commits)

Commit 1: bbc8f0d — 删除 slashcmd 包 + 修正确性 bug + 去重简化 (-229 行)

架构简化: 删除 pkg/slashcmd

slashcmd 包与 tui.Command 存在数据重复(description、aliases 维护两份,需要 catalog_test.go 守卫同步)。改为从 tui.Command 单一来源提取命令元数据:

  • 新增 tui.WebMenuSpecs() 从已有 Command 定义提取 web 菜单 spec
  • 新增 tui.StaticCommands() 导出零值 receiver 安全的命令列表
  • SlashSpec 类型移入 webproto(与 wire format 同包)
  • hub 路由从 slashcmd.Lookup 简化为 3 行 hubCommands map
  • 删除 catalog_test.go(不再有两份数据需要同步)

正确性修复 (P0)

Bug 修复
generateID 纳秒碰撞 → SQLite INSERT OR IGNORE 静默丢数据 crypto/rand 16 字节 hex
sanitizeMessagesForSave else 分支手工拷贝 4 个字段,新增字段被丢弃 out[i] = m 全结构拷贝
proxy truncate 按字节切断多字节字符 → 无效 UTF-8 改为 rune-safe 版本
SetDataDir / DataDir 无锁读写 resolvedDataDir sync.Mutex
Color.Dim\033[90m(bright black)而非 ANSIDim\033[2m faint) 统一为 ANSIDim
stringVal 忽略 float64/bool → timeline 丢失数字类型工具参数 type switch 处理

去重与简化

  • mustJSON 统一到 webproto.MustJSON(消除 3 处重复定义)
  • stripANSI wrapper 删除,直接调用 output.StripANSI
  • dispatch 内联到 dispatchPayload
  • runScanViaAgent / runScanLocally 共享 completeJob(~24 行重复合并)

性能

  • WebSocket upgrader 缓存到 pool 构造期(消除 per-connection 分配)
  • regexp.MustCompile 提升到包级别(消除 per-call 编译)
  • hasTool O(n) → O(1) map 查找
  • isTerminalEvent 使用 slices.Contains

Commit 2: f4e6db2 — 简化实现 (-575 行)

probe 归位

  • pkg/probepkg/agent/probe(probe 依赖 agent.Provider,归属更自然)

删冗余类型/字段

  • 合并 LLMTestRequest / LLMModelsRequestLLMProbeRequest(仅差一个 Model 字段)
  • 删除 ConnTestResponse wrapper(单字段 struct 包 []ConnCheck,直接返回 slice)
  • 删除 ChatPayload.PersistPersistMaxTurns > 0 已隐含 persist,两者从未独立使用)
  • 删除 SlashSpec.WebMenu(构造时始终 true,前端从不读取)
  • embed ChatPayloadSendMessageRequest,消除 handler 中 5 行手工字段拷贝

消除重复调用

  • parseChatPayload 每条 chat 消息只调一次(之前 dispatch + runChatWithAgent 各调一次)
  • extractEventDataforwardAgentEvent 中只调一次(之前每个 switch case 重复调)
  • 内联 snippet / proxyHTTPClient 到唯一调用点

全量构建通过,全部测试通过。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants